package com.itheima.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Setmeal;
import com.itheima.reggie.entity.SetmealDish;
import com.itheima.reggie.entity.dto.PageDto;
import com.itheima.reggie.entity.dto.SetmealDTO;
import com.itheima.reggie.mapper.SetMealMapper;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.SetmealDishService;
import com.itheima.reggie.service.SetmealService;
import com.itheima.reggie.web.R;
import com.itheima.reggie.web.exception.BusinessException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.apache.commons.lang.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 套餐业务层实现类
 *
 * @Author Vsunks.v
 * @Blog blog.sunxiaowei.net/996.mba
 * @Description: 套餐业务层实现类
 */
@Service
@Transactional
public class SetmealServiceImpl extends ServiceImpl<SetMealMapper, Setmeal> implements SetmealService {

    @Autowired
    SetmealDishService setmealDishService;

    @Autowired
    CategoryService categoryService;

    /**
     * 新增套餐(含菜品)
     *
     * @param setmealDTO 套餐(含菜品)
     * @return 是否新增成功
     */
    @Override
    public R saveWithDishes(SetmealDTO setmealDTO) {
        // 1. 如果套餐名称已存在，提示套餐重名
        // String name = setmealDTO.getName();

        checkNameDuplication(setmealDTO);


        // 2. 新增套餐基本信息，返回的套餐id会自动设置进entity
        if (!save(setmealDTO)) {
            return R.fail("新增套餐失败！");
        }

        // 3. 保存套餐菜品明细
        //  3.1 获取新增套餐菜品明细
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();


        //  3.2 遍历获取每个套餐菜品明细，添加套餐id
        Long setmealId = setmealDTO.getId();
        for (SetmealDish setmealDish : setmealDishes) {
            //  3.3 添加套餐id
            setmealDish.setSetmealId(setmealId);
        }


        //  3.4 保存套餐菜品明细
        setmealDishService.saveBatch(setmealDishes);


        return R.success("新增套餐成功", null);
    }

    /**
     * 分页查询套餐基本信息（含套菜分类名称）
     *
     * @param pageDto 分页条件和查询条件
     * @return 符合要求的分页数据
     */
    @Override
    public R<Page<SetmealDTO>> pageWithCategoryName(PageDto pageDto) {
        // 1. 构造分页条件对象page
        Page<Setmeal> setmealPage = new Page<>(pageDto.getPage(), pageDto.getPageSize());

        // 2. 构建查询及排序条件queryWrapper
        LambdaQueryWrapper<Setmeal> qw = Wrappers.lambdaQuery(Setmeal.class)
                .like(StringUtils.isNotBlank(pageDto.getName()), Setmeal::getName, pageDto.getName())
                .orderByDesc(Setmeal::getUpdateTime);

        // 3. 执行分页条件查询
        page(setmealPage, qw);

        // 4. 创建setmealDtoPage并复制基本信息
        // 创建setmealDtoPage
        Page<SetmealDTO> setmealDtoPage = new Page<>();

        // 复制基本信息
        BeanUtils.copyProperties(setmealPage, setmealDtoPage, "records");

        // 5. 查询所有套餐分类信息
        List<Category> categories = categoryService.list(Wrappers.lambdaQuery(Category.class).eq(Category::getType, 2));


        // 6. 遍历setmealPage查询列表数据，根据分类ID查询分类信息，从而获取该菜品的分类名称
        List<SetmealDTO> setmealRecords = setmealPage.getRecords().stream().map(setmeal -> {
            // 6.1 创建setmealDto
            SetmealDTO setmealDTO = new SetmealDTO();
            // 6.2 复制套餐基本信息
            BeanUtils.copyProperties(setmeal, setmealDTO);

            // 6.3 查询并设置分类名称
            Long categoryId = setmeal.getCategoryId();
            String name = "";
            /*  name = categories.stream()
                    .filter(category -> category.getId().equals(categoryId))
                    .map(category -> category.getName())
                    .findFirst().get(); */
            for (Category category : categories) {
                if (category.getId().equals(categoryId)) {
                    name = category.getName();
                    break;
                }
            }

            setmealDTO.setCategoryName(name);

            return setmealDTO;


        }).collect(Collectors.toList());

        // 7. 封装数据回Page并返回R<page>
        setmealDtoPage.setRecords(setmealRecords);
        return R.success(setmealDtoPage);
    }


    /**
     * 批量删除套餐（和套餐详情）
     *
     * @param ids 要删除的套餐id们
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R removeByIdsWithDetails(Long[] ids) {

        // 1. 如果套餐是启用状态，则删除失败。
        // 1.1 构建查询条件：多个id、状态为启用
        // select count(*) from setmeal where id in(1,2,3,4) and status = 1
        LambdaQueryWrapper<Setmeal> cqw = Wrappers.lambdaQuery(Setmeal.class)
                .in(Setmeal::getId, ids)
                .eq(Setmeal::getStatus, 1);


        // 1.2 查询，根据返回结果判断
        if (count(cqw) > 0) {
            throw new BusinessException("套餐售卖中，禁止删除！");
        }

        // 2. 删除套餐详情数据（套餐和菜品的中间表）
        // 2.1 构造删除条件：多个id
        // 尽量少发送SQL语句，可以在一个SQL中删除多个套餐/套餐详情
        // delete from setmeal where setmealId in(1,2,3,4)
        LambdaQueryWrapper<SetmealDish> sdqw = Wrappers.lambdaQuery(SetmealDish.class).in(SetmealDish::getSetmealId, ids);

        // 2.2 删除
        setmealDishService.remove(sdqw);


        // 3. 删除套餐基本信息
        if (!this.removeByIds(Arrays.asList(ids))) {
            throw new BusinessException("删除套餐失败，请稍后再试！");
        }

        // 4. 事务控制
        return R.success("删除套餐成功", null);
    }


    /**
     * 根据条件查询套餐
     *
     * @param setmeal 查询条件
     * @return 符合条件的套餐集合
     */
    @Override
    public R<List<Setmeal>> listByConditions(Setmeal setmeal) {
        Long categoryId = setmeal.getCategoryId();
        Integer status = setmeal.getStatus();
        String name = setmeal.getName();
        String code = setmeal.getCode();
        String description = setmeal.getDescription();

        // 构建查询条件对象
        LambdaQueryWrapper<Setmeal> qw = Wrappers.lambdaQuery(Setmeal.class)
                .eq(categoryId != null, Setmeal::getCategoryId, categoryId)
                .eq(status != null, Setmeal::getStatus, status)
                .like(StringUtils.isNotBlank(name), Setmeal::getName, name)
                .like(StringUtils.isNotBlank(code), Setmeal::getCode, code)
                .like(StringUtils.isNotBlank(description), Setmeal::getDescription, description)
                .orderByDesc(Setmeal::getUpdateTime)
                ;


        //  查询
        List<Setmeal> setmeals = list(qw);

        // 组织数据并返回
        return R.success(setmeals);
    }

    /**
     * 检查名称是否重复，重复则抛出异常
     *
     * @param setmeal 套餐对象
     */
    private void checkNameDuplication(Setmeal setmeal) {
        String name = setmeal.getName();
        int count = count(Wrappers.lambdaQuery(Setmeal.class)
                .eq(Setmeal::getName, name)
                .ne(setmeal.getId() != null, Setmeal::getId, setmeal.getId())
        );
        if (count > 0) {
            throw new BusinessException("套餐名称[ {" + name + "} ]重复，请修改后再试！");
        }
    }
}
